/**
**************************************************************************************************************************
* 
**************************************************************************************************************************
* @file RBTEntityContainer.h
**************************************************************************************************************************/

/**************************************************************************************************************************
* Includes
**************************************************************************************************************************/

#include "RBCommon.h"

#ifdef RB_ENTITY_CONTAINER_COUNT
#ifndef RB_MAX_CONTAINED_ENTITIES
#error "RB_MAX_CONTAINED_ENTITIES must be defined"
#endif

#if RB_ENTITY_CONTAINER_COUNT >= RB_MAX_CONTAINED_ENTITIES
#error "RB_ENTITY_CONTAINER_COUNT must be less than RB_MAX_CONTAINED_ENTITIES"
#endif

#define RB_PP_ENTITY_CONTAINER_CLASS  RBJOIN(RBTEntityContainer,RB_ENTITY_CONTAINER_COUNT)
#define RB_PP_FUNCTION_TEMPLATE_PARMS RB_PP_ENUM_PARAMS(RB_ENTITY_CONTAINER_COUNT, class RBTEntity)
#define RB_PP_FUNCTION_TEMPLATE_PARMS_DERIVED RB_PP_ENUM_PARAMS(RB_ENTITY_CONTAINER_COUNT, class RBTEntity)
#define RB_PP_FUNCTION_TEMPLATE_PARMS_EVAL RB_PP_ENUM_PARAMS(RB_ENTITY_CONTAINER_COUNT, RBTEntity)
#define RB_PP_PARENT_CLASS_CONTAINER RBJOIN(RBTEntityVector, RB_ENTITY_CONTAINER_COUNT)
#define RB_PP_PARENT_CLASS(z, idx, data) public RB_PP_PARENT_CLASS_CONTAINER<RBJOIN(data, idx)>
#define RB_PP_PARENT_CLASSES RB_PP_ENUM(RB_ENTITY_CONTAINER_COUNT, RB_PP_PARENT_CLASS, RBTEntity)

/**************************************************************************************************************************
* Forward declarations
**************************************************************************************************************************/

/**************************************************************************************************************************
* Classes
**************************************************************************************************************************/
template <class T> 
class RB_PP_PARENT_CLASS_CONTAINER
{
public:
    uint32      Size() const { return m_vEntities.size(); }
    T*          Get(uint32 ui) const { return m_vEntities[ui]; }

protected:
    RB_PP_PARENT_CLASS_CONTAINER() {}

    std::vector<T*> m_vEntities;
};


#define ForEachEntity(object, Type, Function) \
    for (uint32 uiEntity=0; uiEntity < object->GetEntityCount<Type>(); ++uiEntity)  \
    {                                                                               \
        Type* entity = object->GetEntity<Type>(uiEntity);                           \
        if (entity) Function;                                                       \
    }                                                                               


template<RB_PP_FUNCTION_TEMPLATE_PARMS>
class RB_PP_ENTITY_CONTAINER_CLASS : RB_PP_PARENT_CLASSES
{
public:
    RB_PP_ENTITY_CONTAINER_CLASS() {}

    template<class T> 
    uint32                      GetEntityCount() {return RB_PP_PARENT_CLASS_CONTAINER<T>::Size();}

    template<class T> 
    T*                          GetEntity(uint32 ui) {return GetEntities<T>()[ui];}

protected:
    template<class T> 
    std::vector<T*>&   GetEntities() {return RB_PP_PARENT_CLASS_CONTAINER<T>::m_vEntities;}

    template<class T> 
    void                        PushBackEntity(T* pEntity)
    {
        GetEntities<T>().push_back(pEntity);
    }

    template<class T> 
    void                        FindAndRemoveEntity(T* pEntity)
    {
        std::vector<T*>& array = GetEntities<T>();
        std::vector<T*>::iterator iter = std::find(array.begin(), array.end(), pEntity);
        if (iter != array.end())
        {
            array.erase(iter);
        }
    }

    template<class T> 
    void                        InsertEntities(RB_PP_PARENT_CLASS_CONTAINER<T>* p)
    {
        for (uint32 ui = 0; ui < p->Size(); ++ui)
        {
            PushBackEntity(p->Get(ui));
        }
    }

};

// Specialization
template< RB_PP_FUNCTION_TEMPLATE_PARMS >
class RBTEntityContainer<RB_PP_FUNCTION_TEMPLATE_PARMS_EVAL> : public RB_PP_ENTITY_CONTAINER_CLASS< RB_PP_FUNCTION_TEMPLATE_PARMS_EVAL >
{

};

/**************************************************************************************************************************/

#endif
